package com.team.childapp.ui.studygarden

import android.content.Intent
import android.graphics.drawable.Drawable
import android.media.AudioManager
import android.media.AudioManager.OnAudioFocusChangeListener
import android.os.Environment
import android.text.TextUtils
import android.util.Log
import android.util.Pair
import android.view.KeyEvent
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import com.bytedance.speech.speechengine.SpeechEngine
import com.bytedance.speech.speechengine.SpeechEngine.SpeechListener
import com.bytedance.speech.speechengine.SpeechEngineDefines
import com.bytedance.speech.speechengine.SpeechEngineGenerator
import com.team.childapp.R
import com.team.childapp.base.App
import com.team.childapp.base.activity.BaseActivity
import com.team.childapp.base.listener.ICallBackResultListener
import com.team.childapp.bean.study.StudyGardenBean
import com.team.childapp.databinding.ActivityStudyGardenBinding
import com.team.childapp.http.StudyGardenLogical
import com.team.childapp.ui.MainActivity
import com.team.childapp.ui.ai.AiGenerateTextByImageActivity
import com.team.childapp.ui.service.ForegroundService
import com.team.childapp.util.LogUtils
import com.team.childapp.util.speechUtils.SensitiveDefines
import com.team.childapp.util.speechUtils.SpeechDemoDefines
import com.team.childapp.util.speechUtils.SpeechStreamPlayer
import com.team.childapp.view.pinyin.PinyinTextView
import org.json.JSONException
import org.json.JSONObject


/**
 * Create on: 2025/1/4
 * by Mr.Zhu
 * Description: TODO
 */
class StudyGardenActivity: BaseActivity<ActivityStudyGardenBinding>(R.layout.activity_study_garden)  {

    private var mAudioManager: AudioManager? = null
    private var mStreamPlayer: SpeechStreamPlayer? = null
    private var mSpeechEngineTTS: SpeechEngine? = null
    private var mDebugPath = ""
    private var pageNum = 1
    private var playStatus = 0 //0是原文，1是译文，2是欣赏

    private var currentBean: StudyGardenBean? = null
    private var mEngineInited = false
    private var mEngineStarted = false
    private var mConnectionCreated = false
    private var mPlayerPaused = false
    private var mPlaybackNowAuthorized = false
    private val mAFChangeListener: OnAudioFocusChangeListener? = null
    private var mCurTtsText = ""
    private var mEngineErrorOccurred = false
    private val mDisablePlayerReuse = false
    override fun initView() {
        title = "学习园地"
        mBinding.studyOriginalTv.setOnClickListener {
            setOriginal(0)
        }
        mBinding.studyTranslationTv.setOnClickListener {
            setOriginal(1)
        }
        mBinding.studyAppreciatingTv.setOnClickListener {
            setOriginal(2)
        }
        mBinding.studyNextTv.setOnClickListener {
            pageNum++
            if (currentBean != null && pageNum > currentBean!!.total) {
                pageNum = currentBean!!.total
            }
            getStudyContent()
        }
        mBinding.studyLastTv.setOnClickListener {
            pageNum--
            if (pageNum < 1) {
                pageNum = 1
            }
            getStudyContent()
        }
        mBinding.tvPlay2.setOnClickListener {
            generatePlayerData()
        }
        mBinding.imageHome.setOnClickListener {
            finish()
        }
        mBinding.imageBack.setOnClickListener {
            finish()
        }
    }
    override fun initData() {
        SpeechEngineGenerator.PrepareEnvironment(applicationContext, application)
        App.application().getHandler().postDelayed(Runnable { getStudyContent() }, 300)
        val serviceIntent = Intent(this, ForegroundService::class.java)
        serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android")
        ContextCompat.startForegroundService(this, serviceIntent)
        mAudioManager = applicationContext.getSystemService(AUDIO_SERVICE) as AudioManager
        if (mStreamPlayer == null) {
            mStreamPlayer = SpeechStreamPlayer()
        }
        if (mDebugPath.isEmpty()) {
            mDebugPath = getDebugPath()
        }
        initEngineTTS()
    }

    private fun getStudyContent() {
        StudyGardenLogical.getInstanceLogin().requestStudyList(
            this,
            pageNum.toString() + "",
            "1", object : ICallBackResultListener {
                override fun onCallBack(result: Any?) {
                    if (result == null) {
                        return
                    }
                    currentBean = result as StudyGardenBean
                    if (currentBean!!.rows != null) {
                        mBinding.studyTitle.setPinyinText(
                            initPinyinTitleData(currentBean!!),
                            PinyinTextView.TYPE_PINYIN_AND_TEXT
                        )
                        mBinding.studyAuthor.setPinyinText(
                            initPinyinAuthorData(currentBean!!),
                            PinyinTextView.TYPE_PINYIN_AND_TEXT
                        )
                        mBinding.studyContent.setNeedChangeLine(true)
                        mBinding.studyContent.setPinyinText(
                            initPinyinContentData(currentBean!!),
                            PinyinTextView.TYPE_PINYIN_AND_TEXT
                        )
                    }
                    resetNextStatus()
                }
            })
    }

    private fun setOriginal(status: Int) {
        playStatus = status
        when (status) {
            0 -> { // 原文
                val backgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffc144_to_dc3618_45, null)
                mBinding.studyOriginalTv.background = backgroundDrawable
                mBinding.studyOriginalTv.setTextColor(ContextCompat.getColor(this, R.color.white))
                val originalBackgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffd8d1_45, null)
                mBinding.studyTranslationTv.background = originalBackgroundDrawable
                mBinding.studyTranslationTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyAppreciatingTv.background = originalBackgroundDrawable
                mBinding.studyAppreciatingTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyContent.visibility = View.VISIBLE
                mBinding.studyContentSmall.visibility = View.GONE
            }
            1 -> { // 译文
                val backgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffc144_to_dc3618_45, null)
                mBinding.studyTranslationTv.background = backgroundDrawable
                mBinding.studyTranslationTv.setTextColor(ContextCompat.getColor(this, R.color.white))
                val originalBackgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffd8d1_45, null)
                mBinding.studyOriginalTv.background = originalBackgroundDrawable
                mBinding.studyOriginalTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyAppreciatingTv.background = originalBackgroundDrawable
                mBinding.studyAppreciatingTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyContentSmall.setPinyinText(
                    currentBean?.let { initPinyinContentTranslationData(it) },
                    PinyinTextView.TYPE_PINYIN_AND_TEXT
                )
                mBinding.studyContent.visibility = View.GONE
                mBinding.studyContentSmall.visibility = View.VISIBLE
            }
            else -> { // 欣赏
                val backgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffc144_to_dc3618_45, null)
                mBinding.studyAppreciatingTv.background = backgroundDrawable
                mBinding.studyAppreciatingTv.setTextColor(ContextCompat.getColor(this, R.color.white))
                val originalBackgroundDrawable: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.shape_ffd8d1_45, null)
                mBinding.studyOriginalTv.background = originalBackgroundDrawable
                mBinding.studyOriginalTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyTranslationTv.background = originalBackgroundDrawable
                mBinding.studyTranslationTv.setTextColor(ContextCompat.getColor(this, R.color.black))
                mBinding.studyContentSmall.setPinyinText(
                    currentBean?.let { initPinyinContentAppreciatingData(it) },
                    PinyinTextView.TYPE_PINYIN_AND_TEXT
                )
                mBinding.studyContent.visibility = View.GONE
                mBinding.studyContentSmall.visibility = View.VISIBLE
            }
        }
    }

    private fun initPinyinTitleData(studyGardenBean: StudyGardenBean): List<Pair<String, String>> {
        val pinyinList: MutableList<Pair<String, String>> = ArrayList()
        if (studyGardenBean.rows.isEmpty()) {
            return pinyinList
        }
        val gardenBean = studyGardenBean.rows[0]
        if (TextUtils.isEmpty(gardenBean.title)) {
            return pinyinList
        }
        val input: List<String> = gardenBean.title.split(" ")
        val pinyin: List<String> = gardenBean.titlePy.split(" ")
        for (i in input.indices) {
            pinyinList.add(Pair.create(input[i], pinyin[i]))
        }
        return pinyinList
    }

    private fun initPinyinAuthorData(studyGardenBean: StudyGardenBean): List<Pair<String, String>> {
        val pinyinList: MutableList<Pair<String, String>> = java.util.ArrayList()
        if (studyGardenBean.rows.isEmpty()) {
            return pinyinList
        }
        val gardenBean = studyGardenBean.rows[0]
        if (TextUtils.isEmpty(gardenBean.auther)) {
            return pinyinList
        }
        val input: List<String> = gardenBean.auther.split(" ")
        val pinyin: List<String> = gardenBean.autherPy.split(" ")
        for (i in input.indices) {
            if (i < pinyin.size) {
                pinyinList.add(Pair.create(input[i],pinyin[i]))
            } else {
                pinyinList.add(Pair.create(input[i], ""))
            }
        }
        return pinyinList
    }

    /**
     * 正文
     * @param studyGardenBean
     * @return
     */
    private fun initPinyinContentData(studyGardenBean: StudyGardenBean): List<Pair<String, String>> {
        val pinyinList: MutableList<Pair<String, String>> = java.util.ArrayList()
        if (studyGardenBean.rows.isEmpty()) {
            return pinyinList
        }
        val gardenBean = studyGardenBean.rows[0]
        if (TextUtils.isEmpty(gardenBean.content)) {
            return pinyinList
        }
        val input: List<String> = gardenBean.content.trim().replace("-", "").split(" ")
        val pinyin: List<String> = gardenBean.contentPy.trim().replace("-", "").split(" ")
        for (i in input.indices) {
            if (i < pinyin.size) {
                pinyinList.add(Pair.create(input[i],pinyin[i]))
            } else {
                pinyinList.add(Pair.create(input[i], ""))
            }
        }
        return pinyinList
    }

    /**
     * 原文
     *
     * @param studyGardenBean
     * @return
     */
    private fun initPinyinContentAppreciatingData(studyGardenBean: StudyGardenBean): List<Pair<String, String>> {
        val pinyinList: MutableList<Pair<String, String>> = java.util.ArrayList()
        if (studyGardenBean.rows.isEmpty()) {
            return pinyinList
        }
        val gardenBean = studyGardenBean.rows[0]
        if (TextUtils.isEmpty(gardenBean.appreciation)) {
            return pinyinList
        }
//        val input: List<String> = gardenBean.appreciation.trim().split("(?<!^)(?!$)")
        val input: List<String> = gardenBean.appreciation.trim().split("")
        for (i in input.indices) {
            pinyinList.add(Pair.create(input[i], ""))
        }
        return pinyinList
    }

    /**
     * 译文
     * @param studyGardenBean
     * @return
     */
    private fun initPinyinContentTranslationData(studyGardenBean: StudyGardenBean): List<Pair<String, String>> {
        val pinyinList: MutableList<Pair<String, String>> = java.util.ArrayList()
        if (studyGardenBean.rows.isEmpty()) {
            return pinyinList
        }
        val gardenBean = studyGardenBean.rows[0]
        if (TextUtils.isEmpty(gardenBean.translation)) {
            return pinyinList
        }
        val input: List<String> = gardenBean.translation.trim().split("")
        for (i in input.indices) {
            pinyinList.add(Pair.create(input[i], ""))
        }
        return pinyinList
    }

    private fun resetNextStatus() {
        when (pageNum) {
            1 -> {
                mBinding.studyLastTv.visibility = View.GONE
                mBinding.studyNextTv.visibility = View.VISIBLE
            }
            currentBean?.total ?: 0 -> {
                mBinding.studyLastTv.visibility = View.VISIBLE
                mBinding.studyNextTv.visibility = View.GONE
            }

            else -> {
                mBinding.studyLastTv.visibility = View.VISIBLE
                mBinding.studyNextTv.visibility = View.VISIBLE
            }
        }
    }

    override fun onDestroy() {
        Log.i(SpeechDemoDefines.TAG, "Asr onDestroy")
        if (mStreamPlayer != null) {
            mStreamPlayer!!.Stop()
        }
        uninitEngine()
        val serviceIntent = Intent(this, ForegroundService::class.java)
        stopService(serviceIntent)
        super.onDestroy()
    }

    private fun generatePlayerData() {
        if (mStreamPlayer != null) {
            mStreamPlayer!!.Stop()
        }
        if (currentBean == null) {
            return
        }
        val gardenBean = currentBean!!.rows[0]
        if (playStatus == 0) {
            mCurTtsText = gardenBean.title + gardenBean.auther + gardenBean.content
        } else if (playStatus == 1) {
            mCurTtsText = gardenBean.translation
        } else {
            mCurTtsText = gardenBean.appreciation
        }
        startEngineBtnClicked()
    }

    private fun startEngineBtnClicked() {
        Log.d(SpeechDemoDefines.TAG, "Start engine, current status: $mEngineStarted")
        if (!mEngineStarted) {
            AcquireAudioFocus()
            if (!mPlaybackNowAuthorized) {
                Log.w(SpeechDemoDefines.TAG, "Acquire audio focus failed, can't play audio")
                return
            }
            //            clearResultText();
            mEngineErrorOccurred = false
            // Directive：启动引擎前调用SYNC_STOP指令，保证前一次请求结束。
            Log.i(SpeechDemoDefines.TAG, "关闭引擎（同步）")
            Log.i(SpeechDemoDefines.TAG, "Directive: DIRECTIVE_SYNC_STOP_ENGINE")
            var ret =
                mSpeechEngineTTS!!.sendDirective(SpeechEngineDefines.DIRECTIVE_SYNC_STOP_ENGINE, "")
            if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
                Log.e(SpeechDemoDefines.TAG, "send directive syncstop failed, $ret")
            } else {
                configStartTtsParams()
                Log.i(SpeechDemoDefines.TAG, "启动引擎")
                Log.i(SpeechDemoDefines.TAG, "Directive: DIRECTIVE_START_ENGINE")
                ret =
                    mSpeechEngineTTS!!.sendDirective(SpeechEngineDefines.DIRECTIVE_START_ENGINE, "")
                if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
                    val message = "发送启动引擎指令失败, $ret"
                    sendStartEngineDirectiveFailed(message)
                }
            }
        }
    }
    private fun sendStartEngineDirectiveFailed(tipText: String) {
        Log.e(SpeechDemoDefines.TAG, tipText)
        this.runOnUiThread {
//            setMyResult(tipText);
            mEngineStarted = false
        }
    }

    private fun AcquireAudioFocus() {
        // 向系统请求 Audio Focus 并记录返回结果
        val res = mAudioManager!!.requestAudioFocus(
            mAFChangeListener, AudioManager.STREAM_MUSIC,
            AudioManager.AUDIOFOCUS_GAIN
        )
        if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
            mPlaybackNowAuthorized = false
        } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            mPlaybackNowAuthorized = true
        }
    }

    private fun configStartTtsParams() {
        //【必需配置】TTS 使用场景
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_SCENARIO_STRING,
            SpeechEngineDefines.TTS_SCENARIO_TYPE_NORMAL
        )

        //        String ttsText = mReferText.getText().toString();
//        if (!ttsText.isEmpty()) {
//            mCurTtsText = ttsText;
//        } else {
        if (TextUtils.isEmpty(mCurTtsText)) {
            mCurTtsText =
                "愿中国青年都摆脱冷气，只是向上走，不必听自暴自弃者流的话。能做事的做事，能发声的发声。有一分热，发一分光。就令萤火一般，也可以在黑暗里发一点光，不必等候炬火。此后如竟没有炬火：我便是唯一的光。"
        }
        //        }
        //【必需配置】需合成的文本，不可超过 80 字
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_TEXT_STRING,
            mCurTtsText
        )
        //【可选配置】需合成的文本的类型，支持直接传文本(TTS_TEXT_TYPE_PLAIN)和传 SSML 形式(TTS_TEXT_TYPE_SSML)的文本
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_TEXT_TYPE_STRING,
            "Plain"
        )
        //【可选配置】用于控制 TTS 音频的语速，支持的配置范围参考火山官网 语音技术/语音合成/离在线语音合成SDK/参数说明 文档
        mSpeechEngineTTS!!.setOptionDouble(
            SpeechEngineDefines.PARAMS_KEY_TTS_SPEED_RATIO_DOUBLE,
            1.0
        )
        //【可选配置】用于控制 TTS 音频的音量，支持的配置范围参考火山官网 语音技术/语音合成/离在线语音合成SDK/参数说明 文档
        mSpeechEngineTTS!!.setOptionDouble(
            SpeechEngineDefines.PARAMS_KEY_TTS_VOLUME_RATIO_DOUBLE,
            1.0
        )
        //【可选配置】用于控制 TTS 音频的音高，支持的配置范围参考火山官网 语音技术/语音合成/离在线语音合成SDK/参数说明 文档
        mSpeechEngineTTS!!.setOptionDouble(
            SpeechEngineDefines.PARAMS_KEY_TTS_PITCH_RATIO_DOUBLE,
            1.0
        )
        //【可选配置】是否在文本的每句结尾处添加静音段，单位：毫秒，默认为 0ms
        mSpeechEngineTTS!!.setOptionInt(SpeechEngineDefines.PARAMS_KEY_TTS_SILENCE_DURATION_INT, 0)

        if (mDisablePlayerReuse) {
            //【可选配置】用于控制 SDK 播放器所用的音源,默认为媒体音源
            // 只有禁用了播放器的复用，在 Start Engine 前配置音源才是生效的
            mSpeechEngineTTS!!.setOptionInt(
                SpeechEngineDefines.PARAMS_KEY_AUDIO_STREAM_TYPE_INT,SpeechEngineDefines.AUDIO_STREAM_TYPE_MEDIA)
        }
        //【可选配置】是否使用 SDK 内置播放器播放合成出的音频，默认为 true
        mSpeechEngineTTS!!.setOptionBoolean(
            SpeechEngineDefines.PARAMS_KEY_TTS_ENABLE_PLAYER_BOOL,false)
        //【可选配置】是否令 SDK 通过回调返回合成的音频数据，默认不返回。
        // 开启后，SDK 会流式返回音频，收到 MESSAGE_TYPE_TTS_AUDIO_DATA_END 回调表示当次合成所有的音频已经全部返回
        mSpeechEngineTTS!!.setOptionInt(
            SpeechEngineDefines.PARAMS_KEY_TTS_DATA_CALLBACK_MODE_INT,2)

        // ------------------------ 在线合成相关配置 -----------------------
        Log.d(SpeechDemoDefines.TAG, "Current online voice: BV700_V2_streaming")
        //【必需配置】在线合成使用的发音人代号
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_VOICE_ONLINE_STRING,
            SensitiveDefines.TTS_DEFAULT_ONLINE_VOICE_TYPE)
        //【必需配置】在线合成使用的音色代号
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_VOICE_TYPE_ONLINE_STRING,
            SensitiveDefines.TTS_DEFAULT_ONLINE_VOICE_TYPE )
        //【可选配置】需要返回详细的播放进度或需要启用断点续播功能时应配置为 1, 否则配置为 0 或不配置
        mSpeechEngineTTS!!.setOptionInt(SpeechEngineDefines.PARAMS_KEY_TTS_WITH_FRONTEND_INT, 1)
        //【可选配置】使用复刻音色
        mSpeechEngineTTS!!.setOptionBoolean(
            SpeechEngineDefines.PARAMS_KEY_TTS_USE_VOICECLONE_BOOL,true)
        //【可选配置】在开启前述使用复刻音色的开关后，制定复刻音色所用的后端集群
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_BACKEND_CLUSTER_STRING,SensitiveDefines.TTS_DEFAULT_CLUSTER)
    }

    private fun initEngineTTS() {
//        mCurTtsWorkMode = mTtsWorkModeArray[mSettings.getOptions(R.string.tts_work_mode_title).chooseIdx];
//        Log.i(SpeechDemoDefines.TAG, "调用初始化接口前的语音合成工作模式为 " + mCurTtsWorkMode);
        // 当使用纯在线模式时，不需要下载离线合成所需资源
        initEngineInternal()
    }

    private fun uninitEngine() {
        if (mSpeechEngineTTS != null) {
            Log.i(SpeechDemoDefines.TAG, "引擎析构.")
            mSpeechEngineTTS!!.destroyEngine()
            mSpeechEngineTTS = null
            Log.i(SpeechDemoDefines.TAG, "引擎析构完成!")
        }
    }

    private fun initEngineInternal() {
        var ret = SpeechEngineDefines.ERR_NO_ERROR
        if (mSpeechEngineTTS == null) {
            Log.i(SpeechDemoDefines.TAG, "创建引擎.")
            mSpeechEngineTTS = SpeechEngineGenerator.getInstance()
            mSpeechEngineTTS?.apply {
                createEngine()
                setContext(applicationContext)
            }
        }

        Log.d(SpeechDemoDefines.TAG, "SDK 版本号: " + mSpeechEngineTTS!!.version)
        Log.i(SpeechDemoDefines.TAG, "配置初始化参数.")
        configInitParamsTTS()

        val startInitTimestamp = System.currentTimeMillis()
        Log.i(SpeechDemoDefines.TAG, "引擎初始化.")
        ret = mSpeechEngineTTS!!.initEngine()
        val errMessage = "初始化失败，返回值: $ret"
        Log.e(SpeechDemoDefines.TAG, errMessage)
        if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
//            String errMessage = "初始化失败，返回值: " + ret;
//            Log.e(SpeechDemoDefines.TAG, errMessage);
            LogUtils.showLog("SpeechDemo", "引擎初始化失败: $errMessage")
            return
        }
        Log.i(SpeechDemoDefines.TAG, "设置消息监听")
        mSpeechEngineTTS!!.setListener(speechListener)

        val cost = System.currentTimeMillis() - startInitTimestamp
        Log.d(SpeechDemoDefines.TAG, String.format("初始化耗时 %d 毫秒", cost))
        speechEnginInitSucceeded(cost)
    }

    private fun speechEnginInitSucceeded(initCost: Long) {
        Log.i(SpeechDemoDefines.TAG, "引擎初始化成功!")
        this.runOnUiThread {
            // setResultText("Initialize cost: " + initCost + "ms.");
            mEngineInited = true
        }
    }
    private val speechListener = SpeechListener { type, data, i1 ->
            var stdData = ""
            stdData = String(data)
            when (type) {
                SpeechEngineDefines.MESSAGE_TYPE_ENGINE_START -> {
                    // Callback: 引擎启动成功回调
                    Log.i(SpeechDemoDefines.TAG, "Callback: 引擎启动成功: data: $stdData")
                    speechStartTTS(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_ENGINE_STOP -> {
                    // Callback: 引擎关闭回调
                    Log.i(SpeechDemoDefines.TAG, "Callback: 引擎关闭: data: $stdData")
                    speechStopTTS(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_ENGINE_ERROR -> {
                    // Callback: 错误信息回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 错误信息: $stdData")
                    speechError(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_SYNTHESIS_BEGIN -> {
                    // Callback: 合成开始回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 合成开始: $stdData")
                    speechStartSynthesis(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_SYNTHESIS_END -> {
                    // Callback: 合成结束回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 合成结束: $stdData")
                    speechFinishSynthesis(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_START_PLAYING -> {
                    // Callback: 播放开始回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 播放开始: $stdData")
                    speechStartPlaying(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_PLAYBACK_PROGRESS -> {
                    // Callback: 播放进度回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 播放进度")
                    speechPlayingProgress(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_FINISH_PLAYING -> {
                    // Callback: 播放结束回调
                    Log.e(SpeechDemoDefines.TAG, "Callback: 播放结束: $stdData")
                    speechFinishPlaying(stdData)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_AUDIO_DATA -> {
                    // Callback: 音频数据回调
                    Log.e(
                        SpeechDemoDefines.TAG,
                        String.format("Callback: 音频数据，长度 %d 字节", stdData.length)
                    )
                    speechTtsAudioData(data, false)
                }

                SpeechEngineDefines.MESSAGE_TYPE_TTS_AUDIO_DATA_END -> {
                    // Callback: 音频数据回调
                    Log.e(
                        SpeechDemoDefines.TAG,
                        String.format("Callback: 音频数据，长度 %d 字节", stdData.length)
                    )
                    speechTtsAudioData(ByteArray(0), true)
                }

                else -> {}
            }
    }

    private fun speechStartTTS(data: String) {
        mEngineStarted = true
        if (mStreamPlayer != null) {
            mStreamPlayer!!.Start()
        }
    }

    private fun speechStopTTS(data: String) {
        mEngineStarted = false
        if ( /*mSettings.getBoolean(R.string.config_demo_player) &&*/mStreamPlayer != null) {
            mStreamPlayer!!.Feed(ByteArray(0), true)
            mStreamPlayer!!.WaitPlayerStop()
        }
        this.runOnUiThread {
            mConnectionCreated = false
            mPlayerPaused = false
        }
        // Abandon audio focus when playback complete
        mAudioManager!!.abandonAudioFocus(mAFChangeListener)
        mPlaybackNowAuthorized = false
    }

    fun speechError(data: String?) {
        this.runOnUiThread {
            try {
                // 从回调的 json 数据中解析错误码和错误详细信息
                val reader = JSONObject(data)
                if (!reader.has("err_code") || !reader.has("err_msg")) {
                    return@runOnUiThread
                }
                //                setResultText(data);
            } catch (e: JSONException) {
                e.printStackTrace()
            }
        }
    }
    private fun speechPlayingProgress(data: String) {
        try {
            val reader = JSONObject(data)
            if (!reader.has("reqid") || !reader.has("progress")) {
                Log.w(SpeechDemoDefines.TAG, "Can't find necessary field in progress callback. ")
                return
            }
            val percentage = reader.getDouble("progress")
            val reqid = reader.getString("reqid")
            Log.d(
                SpeechDemoDefines.TAG,
                "当前播放的文本对应的 reqid: $reqid, 播放进度：$percentage"
            )
        } catch (e: JSONException) {
            e.printStackTrace()
        }
    }

    private fun speechStartSynthesis(data: String) {
    }

    private fun speechFinishSynthesis(data: String) {
    }

    private fun speechStartPlaying(data: String) {
    }
    private fun speechFinishPlaying(data: String) {
    }

    private fun speechTtsAudioData(data: ByteArray, isFinal: Boolean) {
        if (mStreamPlayer != null) {
            mStreamPlayer!!.Feed(data, isFinal)
        }
    }

    private fun configInitParamsTTS() {
        //【必需配置】Engine Name
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_ENGINE_NAME_STRING,
            SpeechEngineDefines.TTS_ENGINE)

        //【必需配置】Work Mode, 可选值如下
        // SpeechEngineDefines.TTS_WORK_MODE_ONLINE, 只进行在线合成，不需要配置离线合成相关参数；
        // SpeechEngineDefines.TTS_WORK_MODE_OFFLINE, 只进行离线合成，不需要配置在线合成相关参数；
        // SpeechEngineDefines.TTS_WORK_MODE_ALTERNATE, 先发起在线合成，失败后（网络超时），启动离线合成引擎开始合成；
        mSpeechEngineTTS!!.setOptionInt(
            SpeechEngineDefines.PARAMS_KEY_TTS_WORK_MODE_INT,
            SpeechEngineDefines.TTS_WORK_MODE_ONLINE)

        //【可选配置】Debug & Log
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_DEBUG_PATH_STRING,mDebugPath)
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_LOG_LEVEL_STRING,
            SpeechEngineDefines.LOG_LEVEL_TRACE )

        //【可选配置】User ID（用以辅助定位线上用户问题）
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_UID_STRING,SensitiveDefines.UID)
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_DEVICE_ID_STRING,SensitiveDefines.DID)

        //【可选配置】是否将合成出的音频保存到设备上，为 true 时需要正确配置 PARAMS_KEY_TTS_AUDIO_PATH_STRING 才会生效
        mSpeechEngineTTS!!.setOptionBoolean(
            SpeechEngineDefines.PARAMS_KEY_TTS_ENABLE_DUMP_BOOL,false)
        // TTS 音频文件保存目录，必须在合成之前创建好且 APP 具有访问权限，保存的音频文件名格式为 tts_{reqid}.wav, {reqid} 是本次合成的请求 id
        // PARAMS_KEY_TTS_ENABLE_DUMP_BOOL 配置为 true 的音频时为【必需配置】，否则为【可选配置】
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_AUDIO_PATH_STRING,mDebugPath)

        //        mDisablePlayerReuse = mSettings.getBoolean(R.string.config_disable_player_reuse);
        //【可选配置】是否禁止播放器对象的复用，如果禁用则每次 Start Engine 都会重新创建播放器对象
        mSpeechEngineTTS!!.setOptionBoolean(
            SpeechEngineDefines.PARAMS_KEY_PLAYER_DISABLE_REUSE_BOOL,false)
        //【可选配置】用于控制 SDK 播放器所用的音源,默认为媒体音源
        // 如果不禁用播放器的复用，必须在 SDK 初始化之前配置音源，其他时机配置无法生效
        mSpeechEngineTTS!!.setOptionInt(
            SpeechEngineDefines.PARAMS_KEY_AUDIO_STREAM_TYPE_INT,
            SpeechEngineDefines.AUDIO_STREAM_TYPE_MEDIA
        )
        //【可选配置】合成出的音频的采样率，默认为 24000
        mSpeechEngineTTS!!.setOptionInt(
            SpeechEngineDefines.PARAMS_KEY_TTS_SAMPLE_RATE_INT,24000)
        //【可选配置】打断播放时使用多长时间淡出停止，单位：毫秒。默认值 0 表示不淡出
        mSpeechEngineTTS!!.setOptionInt(
            SpeechEngineDefines.PARAMS_KEY_AUDIO_FADEOUT_DURATION_INT,20)
        // ------------------------ 在线合成相关配置 -----------------------
        //【必需配置】在线合成鉴权相关：Appid
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_APP_ID_STRING,SensitiveDefines.APPID)
        //【必需配置】在线合成鉴权相关：Token
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_APP_TOKEN_STRING,SensitiveDefines.TOKEN)
        //【必需配置】语音合成服务域名
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_ADDRESS_STRING,SensitiveDefines.DEFAULT_ADDRESS)
        //【必需配置】语音合成服务Uri
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_URI_STRING,SensitiveDefines.TTS_DEFAULT_URI)
        //【必需配置】语音合成服务所用集群
        mSpeechEngineTTS!!.setOptionString(
            SpeechEngineDefines.PARAMS_KEY_TTS_CLUSTER_STRING,
            SensitiveDefines.TTS_DEFAULT_CLUSTER)
        //【可选配置】在线合成下发的 opus-ogg 音频的压缩倍率
        mSpeechEngineTTS!!.setOptionInt(SpeechEngineDefines.PARAMS_KEY_TTS_COMPRESSION_RATE_INT, 10)
    }

    /**
     * get default debug path
     * @return string: debugPath
     * 音频存储路径
     */
    private fun getDebugPath(): String {
        val state = Environment.getExternalStorageState()
        if (Environment.MEDIA_MOUNTED == state) {
            Log.d("SpeechDemo", "External storage can be read and write.")
        } else {
            Log.e("SpeechDemo", "External storage can't write.")
            return ""
        }
        val debugDir = getExternalFilesDir(null) ?: return ""
        if (!debugDir.exists()) {
            if (debugDir.mkdirs()) {
                Log.d("SpeechDemo", "Create debug path successfully.")
            } else {
                Log.e("SpeechDemo", "Failed to create debug path.")
                return ""
            }
        }
        mDebugPath = debugDir.absolutePath
        return mDebugPath
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_F2) {
            val intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
            return true
        }
        if (keyCode == KeyEvent.KEYCODE_BACK ) {
            start<MainActivity>()
            overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
            return true // 表示事件已处理
        }

        return super.onKeyDown(keyCode, event)
    }
}